# -*- coding:utf-8 -*-
import json

from openpyxl.worksheet.worksheet import Worksheet

from app.common.global_values import *

from app.features.enum.edata_type import EDataType as DataType
from app.features.enum.etable_string_key_type import ETableStringKeyType as TableStringKeyType
from app.features.enum.etable_string_value_type import ETableStringValueType as TableStringValueType
from app.features.service.field_info import (
    DataInIndexDefine,
    TableElementDefine,
    TableStringFormatDefine
)

from app.features.service.util import *
from app.features.service.sheet_info import FieldInfo, SheetInfo


class SheetAnalysisUtil:
    def analysis(self, sheet: Worksheet, tableName: str):
        """
        分析excel表,将分析后的数据保存到 SheetInfo
        返回:
            SheetInfo
        """
        # 检查sheet是否合法
        errorMsg = self._sheet_check(tableName, sheet)
        if len(errorMsg) > 1:
            return None, errorMsg
        # 初始化sheet对应的实例
        tableInfo = SheetInfo()
        # 设置sheet名称
        tableInfo.tableName = tableName
        # 解析主键列，将主键列加入到 SheetInfo
        primaryKeyField, nextFieldColumnIndex, errorMsg = self._analysis_primary_key_column(tableName, sheet, tableInfo)
        if primaryKeyField == None or len(errorMsg) > 0:
            return None, errorMsg
        tableInfo.add_field(primaryKeyField)
        # 存储定义过的字段名,h后续检查是否有重名的列，不允许有同名字段
        fieldNames = {}
        # 将主键列加入到 fieldNames 
        fieldNames[tableInfo.get_keyColumn_fieldInfo().fieldName] = 0
        # 解析后面剩余的列
        while nextFieldColumnIndex <= sheet.max_column:
            nextColumnIndex = nextFieldColumnIndex
            oneField, nextFieldColumnIndex, errorMsg = self._analyze_one_field(
                sheet, tableInfo, nextColumnIndex)
            if len(errorMsg) != 0:
                return None, f"表格{tableName}中列号为{nextColumnIndex}的字段存在以下严重错误,导致无法继续:{errorMsg}"
            else:
                # 检查字段名是否重复
                if oneField.fieldName in fieldNames:
                    columnName = get_excel_column_name(fieldNames[oneField.fieldName] + 1)
                    repeatColumnName = get_excel_column_name(oneField.columnSeq + 1)
                    return None, f"表格中存在字段名同为{oneField.fieldName}的字段,分别位于第{columnName}列和第{repeatColumnName}列"
                else:
                    tableInfo.add_field(oneField)
                    fieldNames[oneField.fieldName] = oneField.columnSeq
        # 初始化完毕
        return tableInfo, ""

    def _sheet_check(self, tableName, sheet:Worksheet):
        """
        检查table表中的数据sheet是否合法
        返回:
            errorMsg 错误信息
        """
        if sheet.max_row < 3:
            # 最少也要3行, 1行 字段描述 2行 字段名称  3行数据类型
            return "表:{tableName}表格格式不符合要求,必须在表格前三行中依次声明字段描述、字段名、数据类型"
        if sheet.max_column < 2:
            # 最少也要2列 1列唯一id 1列id对应的数据
            return f"表:{tableName}表格中至少需要2个列,分别为主键列和数据列"
        return ""

    def check_field_name(self, fieldName:str):
        """
        检查字段名是否合法,要求必须以英文字母开头,只能为英文字母、数字或下划线,且不能为空或纯空格
        返回：
            True    合法
            False   不合法
        """
        if len(fieldName.strip()) == 0:
            print("不能为空或纯空格")
            return False
        firstLetter = fieldName[0]
        if not ((firstLetter >= 'a' and firstLetter <= 'z') or (firstLetter >= 'A'and firstLetter <= 'Z')):
            print("%s不合法,必须以英文字母开头", fieldName);
            return False
        for  c in fieldName:
            if not ((c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z') or (c >= '0' and c <= '9') or c == '_'):
                print("%s不合法,含有非法字符\"%c\",只能由英文字母、数字或下划线组成" % (fieldName, c))
                return False
        return True

    def _analysis_primary_key_column(self, tableName, sheet:Worksheet, tableInfo:SheetInfo):
        """
        分析主键列,返回主键列和下一列的index 
        返回:
            primaryKeyField         主键列对象
            nextFieldColumnIndex    下次需要解析的列
            errorMsg                错误信息
        """
        # 解析前三行第一列(主键列,要求数据类型为int、long或string且数据非空、唯一)
        # 主键列名称
        primaryKeyColumnTypeName = str(
            sheet.cell(DATA_FIELD_DATA_TYPE_INDEX, 1).value)
        # 主键列类型
        primaryKeyColumnType = self._analyze_data_type(primaryKeyColumnTypeName)
        if not (primaryKeyColumnType == DataType.Int.value or primaryKeyColumnType == DataType.Long.value or primaryKeyColumnType == DataType.String):
            return None, None, "主键列的类型只能为int、long或string"
        # 解析主键列
        primaryKeyField, nextFieldColumnIndex, errorMsg = self._analyze_one_field(
            sheet, tableInfo, 1)
        if len(errorMsg) != 0:
            return None, None, f"表格{tableName}中列{1}的字段存在以下严重错误,导致无法继续:{errorMsg}"
        # 主键唯一性检查
        if len(primaryKeyField.data) != len(set(primaryKeyField.data)):
            return None, None, f"{tableName}主键列存在重复错误"
        # 主键如果是string型,检查每行否符合变量名的规范
        if primaryKeyColumnType == DataType.String.value:
            for row in range(0, len(primaryKeyField.data)):
                if not self.check_field_name(str(primaryKeyField.data[row])):
                    return None, None, f"第{row}行所填主键字符串不符合命名规范"
        return primaryKeyField, nextFieldColumnIndex, ""

    def _analyze_data_type(self, inputTypeString: str):
        """
        根据excel类型字符串转化为内部使用的类型
        返回
            类型定义的字符串转化位对应的数据类型 DataType
        """
        # 判空
        if len(inputTypeString) == 0:
            return DataType.Invalid.value
        # 左右去空格
        typeString = inputTypeString.strip()
        # 匹配类型
        if typeString.startswith("int"):
            return DataType.Int.value
        if typeString.startswith("long"):
            return DataType.Long.value
        elif typeString.startswith("float"):
            return DataType.Float.value
        elif typeString.startswith("string"):
            return DataType.String.value
        elif typeString.startswith("bool"):
            return DataType.Bool.value
        elif typeString.startswith("date"):
            return DataType.Date.value
        elif typeString.startswith("array"):
            return DataType.Array.value
        elif typeString.startswith("dict"):
            return DataType.Dict.value
        elif typeString.startswith("tableString"):
            return DataType.TableString.value
        else:
            return DataType.Invalid.value

    def _analyze_one_field(self, dt: Worksheet, tableInfo: SheetInfo,  columnIndex: int):
        """
        解析一列的数据,组织成FieldInfo类,并返回FieldInfo,包括字段类型,说明和数据z
        返回:
            FieldInfo               当前列解析后的数据
            nextFieldColumnIndex    下次要解析列index
            errorMsg                错误信息
        """
        errorMsg = ""
        # 下一个要处理的列
        nextFieldColumnIndex = columnIndex + 1
        # 判断列号是否越界
        if columnIndex > dt.max_column:
            return None, nextFieldColumnIndex, f"{inputFieldName}需要解析的列号越界,可能因为dict或array中实际的子元素个数低于声明的个数"
        fieldInfo = FieldInfo()
        # 列所在表格sheet名称
        fieldInfo.tableName = tableInfo.tableName
        # 列种字段描述中的换行全替换为空格
        fieldInfo.desc = str(dt.cell(DATA_FIELD_DESC_INDEX, columnIndex).value).replace(
            '\n', ' ').replace('\r', ' ').replace('\t', ' ')
        # 列在sheet中的列号
        fieldInfo.columnSeq = columnIndex
        # 数据列对应的配置字段名称
        inputFieldName = str(
            dt.cell(DATA_FIELD_NAME_INDEX, columnIndex).value).strip()
        # 检查定义类型字段名是否合法
        if not self.check_field_name(inputFieldName):
            return None, columnIndex, "字段命名不合法"
        else:
            fieldInfo.fieldName = inputFieldName
        # 读取填写的数据类型
        fieldInfo.dataTypeString = str(
            dt.cell(DATA_FIELD_DATA_TYPE_INDEX, columnIndex).value).strip()
        # 设置列的数据类型
        fieldInfo.dataType = self._analyze_data_type(fieldInfo.dataTypeString)
        # 按照类型解析每行的数据，内部会把数据fieldInfo 增加到对应的列表中
        if fieldInfo.dataType == DataType.Int.value:
            self._analyze_int_type(fieldInfo, dt, columnIndex)
            print("_analyze_int_type 解析后的数据为:", json.dumps(fieldInfo.data))
        elif fieldInfo.dataType == DataType.Long.value:
            self._analyze_long_type(fieldInfo, dt, columnIndex)
            print("_analyze_long_type 解析后的数据为:", json.dumps(fieldInfo.data))
        elif fieldInfo.dataType == DataType.Float.value:
            self._analyze_float_type(fieldInfo, dt, columnIndex)
            print("_analyze_float_type 解析后的数据为:", json.dumps(fieldInfo.data))
        elif fieldInfo.dataType == DataType.Bool.value:
            self._analyze_bool_type(fieldInfo, dt, columnIndex)
            print("_analyze_bool_type 解析后的数据为:", json.dumps(fieldInfo.data))
        elif fieldInfo.dataType == DataType.String.value:
            self._analyze_string_type(fieldInfo, dt, columnIndex)
            print("_analyze_string_type 解析后的数据为:", json.dumps(fieldInfo.data))
        elif fieldInfo.dataType == DataType.Array.value:
            self._analyze_array_type(fieldInfo, dt, columnIndex)
            print("_analyze_array_type 解析后的数据为:", json.dumps(fieldInfo.data))
        elif fieldInfo.dataType == DataType.Dict.value:
            self._analyze_dict_type(fieldInfo, dt, columnIndex)
            print("_analyze_dict_type 解析后的数据为:", json.dumps(fieldInfo.data))
        elif fieldInfo.dataType == DataType.TableString.value:
            self._analyze_table_string_type(fieldInfo, dt, columnIndex)
            print("_analyze_table_string_type 解析后的数据为:", json.dumps(fieldInfo.data))
        else:
            errorMsg = "数据类型无效,填写的为:" + fieldInfo.dataTypeString

        if len(errorMsg) > 0:
            return None, nextFieldColumnIndex, errorMsg
        # 没有任何错误返回字段信息
        return fieldInfo, nextFieldColumnIndex, errorMsg
        

    def _analyze_int_type(self, fieldInfo: FieldInfo, dt: Worksheet,  columnIndex: int):
        """
        解析int类型
        返回out FieldInfo, out bool
        """
        fieldInfo.data = []
        # 记录非法数据的行号以及数据值(key:行号 int , value:数据值 string)
        invalidInfo = {}
        for row in range(DATA_FIELD_DATA_START_INDEX, dt.max_row+1):
            print("row:%d" % (row))
            # 如果本行该字段的父元素标记为无效则该数据也标为无效
            inputData = str(dt.cell(row, columnIndex).value).strip()
            print("inputData:"+inputData)
            if len(inputData) == 0:
                invalidInfo[row] = inputData
            else:
                if inputData.isdigit():
                    fieldInfo.data.append(int(inputData))
                else:
                    invalidInfo[row] = inputData

        # 如果有错误,把错误输出
        if len(invalidInfo) > 0:
            invalidDataInfo = "以下行中数据不是合法的int类型的值:\n"
            for key in invalidInfo.keys():
                invalidDataInfo += "第" + \
                    str(key+1)+"行,错误地填写数据为:"+invalidInfo[key]+"\n"
            print(invalidDataInfo)
            return False
        else:
            return True

    def _analyze_long_type(self, fieldInfo: FieldInfo, dt: Worksheet,  columnIndex: int):
        """
        解析long类型
        返回out FieldInfo, out bool
        """
        fieldInfo.data = []
        # 记录非法数据的行号以及数据值(key:行号 int , value:数据值 string)
        invalidInfo = {}
        for row in range(DATA_FIELD_DATA_START_INDEX, dt.max_row+1):
            print("row:%d" % (row))
            inputData = str(dt.cell(row, columnIndex).value).strip()
            print("inputData:"+inputData)
            if len(inputData) == 0:
                invalidInfo[row] = inputData
            else:
                if inputData.isdigit():
                    fieldInfo.data.append(int(inputData))
                else:
                    invalidInfo[row] = inputData

        # 如果有错误,把错误输出
        if len(invalidInfo) > 0:
            invalidDataInfo = "以下行中数据不是合法的int类型的值:\n"
            for key in invalidInfo.keys():
                invalidDataInfo += "第" + \
                    str(key+1)+"行,错误地填写数据为:"+invalidInfo[key]+"\n"
            print(invalidDataInfo)
            return False
        else:
            return True
   
    def _analyze_float_type(self, fieldInfo: FieldInfo, dt: Worksheet,  columnIndex: int):
        """
        解析Float类型
        返回out FieldInfo, out bool
        """
        fieldInfo.data = []
        # 记录非法数据的行号以及数据值(key:行号 int , value:数据值 string)
        invalidInfo = {}
        for row in range(DATA_FIELD_DATA_START_INDEX, dt.max_row+1):
            print("row:%d" % (row))
            inputData = str(dt.cell(row, columnIndex).value).strip()
            print("inputData:"+inputData)
            if len(inputData) == 0:
                invalidInfo[row] = inputData
            else:
                if inputData.isdigit():
                    fieldInfo.data.append(float(inputData))
                else:
                    invalidInfo[row] = inputData

        # 如果有错误,把错误输出
        if len(invalidInfo) > 0:
            invalidDataInfo = "以下行中数据不是合法的int类型的值:\n"
            for key in invalidInfo.keys():
                invalidDataInfo += "第" + \
                    str(key+1)+"行,错误地填写数据为:"+invalidInfo[key]+"\n"
            print(invalidDataInfo)
            return False
        else:
            return True

    def _analyze_bool_type(self, fieldInfo: FieldInfo, dt: Worksheet,  columnIndex: int):
        """
        解析Bool类型
        返回out FieldInfo, out bool
        """
        fieldInfo.data = []
        # 记录非法数据的行号以及数据值(key:行号 int , value:数据值 string)
        invalidInfo = {}
        for row in range(DATA_FIELD_DATA_START_INDEX, dt.max_row+1):
            print("row:%d" % (row))
            inputData = str(dt.cell(row, columnIndex).value).strip()
            print("inputData:"+inputData)
            if len(inputData) == 0:
                invalidInfo[row] = inputData
            else:
                if "1" == inputData or "true" == inputData:
                    fieldInfo.data.append(True)
                elif "0" == inputData or "false" == inputData:
                    fieldInfo.data.append(False)
                else:
                    invalidInfo[row] = inputData

        # 如果有错误,把错误输出
        if len(invalidInfo) > 0:
            invalidDataInfo = "以下行中数据不是合法的int类型的值:\n"
            for key in invalidInfo.keys():
                invalidDataInfo += "第" + \
                    str(key+1)+"行,错误地填写数据为:"+invalidInfo[key]+"\n"
            print(invalidDataInfo)
            return False
        else:
            return True

    def _analyze_string_type(self, fieldInfo: FieldInfo, dt: Worksheet,  columnIndex: int):
        """
        解析String类型
        返回out FieldInfo, out bool
        """
        fieldInfo.data = []
        # 记录非法数据的行号以及数据值(key:行号 int , value:数据值 string)
        invalidInfo = {}
        for row in range(DATA_FIELD_DATA_START_INDEX, dt.max_row+1):
            print("row:%d" % (row))
            inputData = str(dt.cell(row, columnIndex).value).strip()
            print("inputData:"+inputData)
            if len(inputData) == 0:
                invalidInfo[row] = inputData
            else:
                fieldInfo.data.append(str(inputData))

        # 如果有错误,把错误输出
        if len(invalidInfo) > 0:
            invalidDataInfo = "以下行中数据不是合法的int类型的值:\n"
            for key in invalidInfo.keys():
                invalidDataInfo += "第" + \
                    str(key+1)+"行,错误地填写数据为:"+invalidInfo[key]+"\n"
            print(invalidDataInfo)
            return False
        else:
            return True

    def _analyze_table_string_type(self, fieldInfo: FieldInfo, dt: Worksheet,  columnIndex: int):
        """
        解析tableString型数据的定义,将其格式解析为TableStringFormatDefine类,但填写的数据直接以字符串形式存在FieldInfo的Data变量中
        说明:
            类型定义:tableString[k:#seq|v:#table(skeleton=#1(string),typeId=#2(int))]
        """
        # 定义错误信息字符串
        errorMsg = ""
        # 检查定义字符串是否合法并转为TableStringFormatDefine的定义结构
        fieldInfo.tableStringFormatDefine, errorMsg = self._get_table_string_format_define(
            fieldInfo.dataTypeString)
        if len(errorMsg) != 0:
            errorMsg = "tableString格式定义错误,"+errorMsg + \
                ",你输入的类型定义字符串为:"+fieldInfo.dataTypeString
            print(errorMsg)
            return False

        # 将填写的数据直接以字符串形式存在FieldInfo的Data变量中
        fieldInfo.data = []
        for row in range(DATA_FIELD_DATA_START_INDEX, dt.max_row+1):
            print("row:%d" % (row))
            inputData = str(dt.cell(row, columnIndex).value).strip()
            if len(inputData) != 0:
                fieldInfo.data.append(str(inputData))
        return True

    def _get_table_string_format_define(self, dataTypeString:str):
        """
        解析类型的定义
        返回:TableStringFormatDefine 和 errorMsg
        """
        formatDefine = TableStringFormatDefine()
        # 必须在tableString[]中声明格式
        DEFINE_START_STRING = "tableString["
        if not dataTypeString.startswith(DEFINE_START_STRING) and not dataTypeString.rindex("]"):
            errorMsg = "必须在tableString[]中声明,即以\"tableString[\"开头,以\"]\"结尾"
            return formatDefine, errorMsg
        # 去掉外面的tableString[],取得中间定义内容k:#seq|v:#table(skeleton=#1(string),typeId=#2(int))
        startIndex = len(DEFINE_START_STRING)
        endIndex = len(dataTypeString) - 1
        formatString = str(dataTypeString[startIndex:endIndex]).strip()
        print("debug formatString:", formatString)
        # 通过|分离key和value的声明
        keyAndValueFormatString = formatString.split('|')
        if len(keyAndValueFormatString) != 2:
            errorMsg = "必须用|分隔key和value"
            return formatDefine, errorMsg
        # 解析key声明
        KEY_START_STRING = 'k:'
        keyFormatString = str(keyAndValueFormatString[0]).strip()
        if not keyFormatString.startswith(KEY_START_STRING):
            errorMsg = "key的声明必须以k:开头"
            return formatDefine, errorMsg
        else:
            # 去除开头的k:
            keyFormatString = keyFormatString[len(KEY_START_STRING):].strip()
            # 按数据顺序自动编号
            if keyFormatString == "#seq":
                formatDefine.keyDefine.keyType = TableStringKeyType.Seq.value
            # 以数据组中指定索引位置的数据为key
            elif keyFormatString.startswith("#"):
                formatDefine.keyDefine.keyType = TableStringKeyType.DataInIndex.value
                formatDefine.keyDefine.dataInIndexDefine, errorMsg = self._get_data_in_index_define(
                    keyFormatString)
                if len(errorMsg) != 0:
                    errorMsg = "key的声明未符合形如#1(int)" + errorMsg
                    return formatDefine, errorMsg

                # 只有int、long或string型数据才能作为key
                if not (formatDefine.keyDefine.dataInIndexDefine.dataType == DataType.Int.value or
                        formatDefine.keyDefine.dataInIndexDefine.dataType == DataType.Long.value or
                        formatDefine.keyDefine.dataInIndexDefine.dataType == DataType.String.value):
                    errorMsg = "key只允许为int、long或string型,你定义的类型为" + \
                        formatDefine.keyDefine.dataInIndexDefine.dataType
                    return formatDefine, errorMsg
            else:
                errorMsg = "key声明非法"
                return formatDefine, errorMsg
        # 解析value声明
        valueFormatString = str(keyAndValueFormatString[1]).strip()
        VALUE_START_STRING = "v:"
        if not valueFormatString.startswith(VALUE_START_STRING):
            errorMsg = "value的声明必须以v:开头"
            print(errorMsg)
            return formatDefine, errorMsg
        else:
            # 去除开头的v:
            valueFormatString = valueFormatString[len(VALUE_START_STRING):].strip()
            # value始终为true
            if valueFormatString == "#true":
                formatDefine.valueDefine.ValueType = TableStringValueType.AllTrue.value
            # value为table类型
            elif valueFormatString.startswith("#table"):
                formatDefine.valueDefine.ValueType = TableStringValueType.Table.value
                # 判断是否形如#table(xxx)
                leftBracketIndex = valueFormatString.index('(')
                rightBracketIndex = valueFormatString.rindex(')')
                if leftBracketIndex == -1 or rightBracketIndex != len(valueFormatString) - 1:
                    errorMsg = "table类型value格式声明错误,必须形如#table(xxx)"
                    return formatDefine, errorMsg
                else:
                    # 去掉#table(xxx)外面,只保留括号中的内容
                    tableDefineString = valueFormatString[leftBracketIndex +
                                                          1:rightBracketIndex].strip()
                    print("debug tableDefineString:", tableDefineString)
                    # table中每个键值对的声明用英文逗号隔开
                    tableElementDefine = tableDefineString.split(',')
                    print("debug tableElementDefine:", tableElementDefine)
                    # 解析每个键值对的定义,形如type=#1(int)
                    formatDefine.valueDefine.TableValueDefineList = []
                    # 记录每个键值对的key和索引位置,不允许重复(key:key名 string, value:第几组键值对 int,从0开始记)
                    tableKeys = {}
                    for i in range(len(tableElementDefine)):
                        oneTableElementDefine, errorMsg = self._get_table_element_define(
                            tableElementDefine[i].strip())
                        print("debug oneTableElementDefine.keyName:",
                              oneTableElementDefine.keyName)
                        if len(errorMsg) != 0:
                            errorMsg = "table类型值声明错误,无法解析" + \
                                tableElementDefine[i].strip(
                                ) + "," + errorMsg
                            return formatDefine, errorMsg
                        else:
                            # 检查定义的key是否重复
                            if oneTableElementDefine.keyName in tableKeys.keys():
                                errorMsg = "table类型的第"+(tableKeys[oneTableElementDefine.keyName]+1)+"个与第"+(
                                    i + 1)+"个子元素均为相同的key("+oneTableElementDefine.keyName+")"
                                return formatDefine, errorMsg
                            else:
                                # 增加keyName 索引
                                tableKeys[oneTableElementDefine.keyName] = i + 1
                                formatDefine.valueDefine.TableValueDefineList.append(
                                    oneTableElementDefine)
            # 以数据组中指定索引位置的数据为value
            elif valueFormatString.index("#"):
                formatDefine.valueDefine.ValueType = TableStringValueType.DataInIndex.value
                formatDefine.valueDefine.DataInIndexDefine, errorMsg = self._get_data_in_index_define(
                    valueFormatString)
                if len(errorMsg) > 0:
                    errorMsg = "value的声明未符合形如#1(int)\n" + errorMsg
                    return formatDefine, errorMsg
            else:
                errorMsg = "value声明非法"
                return formatDefine, errorMsg

        return formatDefine, errorMsg

    def _get_table_element_define(self, tableElementDefine: str):
        """
        将形如type=#1(int)的格式定义字符串转为TableElementDefine定义
        返回:TableElementDefine
        """
        elementDefine = TableElementDefine()
        # 判断是否用=分隔key与value定义string[]
        keyAndValueString = tableElementDefine.strip().split('=')
        print("debug keyAndValueString:", keyAndValueString)
        if len(keyAndValueString) != 2:
            errorMsg = "必须用=分隔键值对"
            print(errorMsg)
            return elementDefine, errorMsg
        else:
            # 取得并检查key名
            elementDefine.keyName = keyAndValueString[0].strip()
            if not self.check_field_name(elementDefine.keyName):
                errorMsg = "键值对中键名非法," + errorMsg
                print(errorMsg)
                return elementDefine, errorMsg
            # 解析value的定义
            elementDefine.dataInIndexDefine, errorMsg = self._get_data_in_index_define(
                keyAndValueString[1].strip())
            if len(errorMsg) != 0:
                errorMsg = "键值对中value的声明未符合形如#1(int)\n" + errorMsg
                print(errorMsg)
                return elementDefine, errorMsg

        return elementDefine, errorMsg

    def _get_data_in_index_define(self, defineString:str):
        """
        将形如#1(int)的格式定义字符串转为DataInIndexDefine定义
        返回 DataInIndexDefine 和 errorMsg
        """
        errorMsg = ""
        dataInIndexDefine = DataInIndexDefine()
        # 检查#后是否跟合法数字,且数字后面用括号注明类型
        defineString = defineString[1:].strip()
        # 检查类型是否合法
        leftBracketIndex = defineString.index('(')
        rightBracketIndex = defineString.rindex(')')
        if leftBracketIndex == -1 or rightBracketIndex != len(defineString) - 1:
            errorMsg = "未注明格式类型,需要形如:#1(int)"
            print(errorMsg)
            return dataInIndexDefine, errorMsg
        else:
            dataTypeString = defineString[leftBracketIndex +
                                          1: rightBracketIndex].strip()
            dataInIndexDefine.dataType = self._analyze_data_type(dataTypeString)

            if not (dataInIndexDefine.dataType == DataType.Int.value or
                    dataInIndexDefine.dataType == DataType.Long.value or
                    dataInIndexDefine.dataType == DataType.Float.value or
                    dataInIndexDefine.dataType == DataType.Bool.value or
                    dataInIndexDefine.dataType == DataType.String.value):
                errorMsg = "格式类型非法,只支持int、long、float、bool、string这几种类型"
                return dataInIndexDefine, errorMsg

        # 检查数据索引值是否合法
        dataIndexString = defineString[0:leftBracketIndex].strip()
        dataIndex = int(dataIndexString)
        if dataIndex > 0:
            dataInIndexDefine.dataIndex = dataIndex
        else:
            errorMsg = "数据索引值编号最小要从1开始"
            return dataInIndexDefine, errorMsg

        return dataInIndexDefine, errorMsg
    
    def _analyze_array_type(self, fieldInfo: FieldInfo, dt: Worksheet,  columnIndex: int):
        """
        解析如array[type:n](type为类型,n为array中元素个数)的array类型的声明字符串,获得子元素的类型以及子元素的个数
        最多是二维数组
        返回  string dataTypeString,  DataType dataType,  int childCount, string errorMsg
        """
        # 解析array声明的子元素的数据类型和个数
        dataTypeString = ""
        dataType = DataType.Invalid
        # 数据元素个数
        rows = 0
        dataTypeString, dataType, rows, errorMsg = self._get_array_string_format_define(fieldInfo.dataTypeString)
        if len(errorMsg) > 0:
            return False, errorMsg
        # 存储子类型的类型以及类型定义字符串
        fieldInfo.arrayChildDataTypeString = dataTypeString
        fieldInfo.arrayChildDataType = dataType
        # 解析之后的几列作为array的下属元素
        fieldInfo.childField = []
        # 如果array的子元素为array或dict类型,当前面的子元素用-1标识为无效后,
        # 后面的数据也必须声明为无效的,比如用array[dict[3]:5]表示一场推图战斗胜利最多可获得的5种奖励物,
        # 如果某一行对应的关卡至多只有3种奖励物,则必须填在前3个子元素列中,后面2个声明为无效
        if fieldInfo.arrayChildDataType == DataType.Array or fieldInfo.arrayChildDataType == DataType.Dict:
            dataTypeString, dataType, rows, errorMsg = self._get_array_string_format_define(fieldInfo.dataTypeString)
        # 将填写的数据直接以字符串形式存在FieldInfo的Data变量中
        fieldInfo.data = []
        for row in range(DATA_FIELD_DATA_START_INDEX, dt.max_row+1):
            print("row:%d" % (row))
            inputData = str(dt.cell(row, columnIndex).value).strip()
            if len(inputData) != 0:
                fieldInfo.data.append(str(inputData))
        return True, ""

    def _get_array_string_format_define(self, defineString:str):
        """
        解析如array[type:n](type为类型,n为array中元素个数)的array类型的声明字符串,获得子元素的类型以及子元素的个数
        返回  string typeString,  DataType dataType,  int childCount, string errorMsg
        """
        # 
        dataTypeString = ""
        dataType = DataType.Invalid
        count = 0
        errorMsg = ""

        leftBracketIndex = defineString.index('[')
        rightBracketIndex = defineString.rindex(']')
        # 判断格式是否合法
        if leftBracketIndex != -1 and rightBracketIndex != -1 and leftBracketIndex < rightBracketIndex:
            # 去掉首尾包裹的array[]
            typeAndCountString = defineString[leftBracketIndex +1, rightBracketIndex].strip()
            dataTypeString = typeAndCountString
            # 通过冒号分离类型和个数(注意不能用Split分隔,可能出现array[array[int:2]:3]这种嵌套结构,必须去找最后一个冒号的位置)
            lastColonIndex = typeAndCountString.rindex(':')
            if lastColonIndex == -1:
                # 没有冒号的情况，就是格式错误
                errorMsg = "array类型数据声明不合法,请采用array[type:n]的形式,冒号分隔类型与个数的定义,你填写的类型为:"+defineString
                return dataTypeString, dataType, count, errorMsg
            else:
                # 类型字符串
                typeString = typeAndCountString[0, lastColonIndex].strip()
                # 元素数量字符串
                countString = typeAndCountString[lastColonIndex + 1,
                                                 len(typeAndCountString) - lastColonIndex - 1].strip()
                # 判断定义元素类型是否合法
                inputChildDataType = self._analyze_data_type(typeString)
                if inputChildDataType == DataType.Invalid:
                    errorMsg = "array类型数据声明不合法,子类型错误,你填写的类型为:" + defineString
                    return dataTypeString, dataType, count, errorMsg
                dataType = inputChildDataType
                # 判断个数是否合法,是否是数字
                if not countString.isdigit():
                    errorMsg = "array类型数据声明不合法,声明的下属元素个数不是合法的数字,你填写的个数为:" + countString
                    return dataTypeString, dataType, count, errorMsg
                count = int(countString)
                # 判断数字是否填写小于1的
                if count < 1:
                    errorMsg = "array类型数据声明不合法,声明的下属元素个数不能低于1个,你填写的个数为:" + countString
                    return dataTypeString, dataType, count, errorMsg
                # 正常返回
                return dataTypeString, dataType, count, errorMsg
        else:
            errorMsg = "array类型数据声明不合法,请采用array[type:n]的形式,其中type表示类型,n表示array中元素个数,你填写的类型为:" + defineString
            return dataTypeString, dataType, count, errorMsg

    def _analyze_dict_type(self, fieldInfo:FieldInfo, tableInfo, dt, columnIndex):
        return True, ""

    def _get_dict_childcount(self, defineString:str):
        """
        解析形如dict[n](n为子元素个数)的dict类型的声明字符串,获得子元素的个数
        返回:子元素的个数,错误信息
        """
        childCount = 0
        leftBracketIndex = defineString.index('[')
        rightBracketIndex = defineString.rindex(']')
        if leftBracketIndex != -1 and rightBracketIndex != -1 and leftBracketIndex < rightBracketIndex:
            # 取出括号中的数字,判断是否合法
            countString = str(defineString[leftBracketIndex + 1, rightBracketIndex - leftBracketIndex - 1])
            if countString.isdigit() == False:
                return -1, f"dict类型数据声明不合法,声明的下属元素个数不是合法的数字,你填写的个数为{countString}"
            
            childCount = int(countString)
            if childCount < 1:
                return -1, f"dict类型数据声明不合法,声明的下属元素个数不能低于1个,你填写的个数为{countString}"

            return childCount, ""
        else:
            return -1, f"dict类型数据声明不合法,请采用dict[n]的形式,其中n表示下属元素个数,你填写的类型为{defineString}"